#include<iostream>
#include<vector>
#include<string>
#include<boost/filesystem.hpp>
#include"util.hpp"
#include"log.hpp"

//指定所有html网页文件的所有路径
const std::string src_path="data/input";
//指定保存 所有html网页文件去标签并且分析之后的数据 的文件路径
const std::string output="data/raw_html/raw.txt";

//创建一个结构体，用于保存，一个html网页文件分析之后的 title，content，url
typedef struct DocInfo{
    std::string title;   //网页文件的标题
    std::string content; //网页文件的内容
    std::string url;     //网页文件的url
}DocInfo_t;


//声明对应3步关键函数
bool EnumFile(const std::string& src_path,std::vector<std::string>*file_list);
bool ParseHtml(const std::vector<std::string>&file_list,std::vector<DocInfo_t>* results);
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output);


int main()
{

  //1：递归式的获取input目录下的所有html网页文件的文件名称和路径，保存到file_list中
  std::vector< std::string> file_list;
  if(!EnumFile(src_path,&file_list))
  {
   // std::cerr<<"enum file name error!"<<std::endl;
   LOG(WARNING,"enum file name error!");
    return 1;
  }


  //2.读取file_list中对应的文件的内容，进行分析，将分析之后的数据放入 results中
  std::vector<DocInfo_t> results;
  if(!ParseHtml(file_list,&results))
  {
     // std::cerr<<"parse html error!"<<std::endl;
      LOG(WARNING,"parse html error!");
      return 2;
  }

  //3.将results中保存的每个html页面文件分析之后的数据写入raw.txt中
  if(!SaveHtml(results,output))
  {

    //  std::cerr<<"save html error!"<<std::endl;
    LOG(WARNING,"save html error!"); 
    return 3;
  }
  
  return 0;

}



bool EnumFile(const std::string& src_path,std::vector<std::string>*file_list)
{
  namespace fs=boost::filesystem;
  fs::path root_path(src_path);

  //判断路径是否存在，如果不存在直接返回false
  if(!fs::exists(root_path))
  {
   // std::cerr<<src_path<<"not exists"<<std::endl;
    LOG(WARNING,src_path+"not exists!");
    return false;
  }

  //定义一个空迭代器，用来判断递归是否结束
  fs::recursive_directory_iterator end;
  for(fs::recursive_directory_iterator iter(root_path);iter!=end;iter++)
  {
    //判断当前路径是否对应的是普通文件，目录就不是普通文件
    if(!fs::is_regular_file(*iter))
    {
      continue;
    }
    //是普通文件，判断是否是html文件
    if(iter->path().extension()!=".html")
    {
      continue;
    }
    //当前路径对应的是html文件，将该路径保存到file_list中
    file_list->push_back(iter->path().string());    
  }

    return true;
}


bool ParseTitle(const std::string& result,std::string * title)
{
  std::size_t begin=result.find("<title>");
  if(begin==std::string::npos)
  {
    return false;
  }

  std::size_t end=result.find("</title>");

  //截取字符串，但是截取的字符串应该是左闭右开区间
  begin+=std::string("<title>").size();
  if(begin>end)
  {
    return false;
  }
  *title= result.substr(begin,end-begin);
  return true;
}


bool ParseContent(const std::string& result,std::string* content)
{
  //去标签，基于一个简单的状态机
  enum status{
    LABLE,//表示标签
    CONTENT//表示正文内容
  };
  
  enum status s=LABLE;
  for(char c:result)
  {
    switch(s)
    {
      case LABLE:
        if(c=='>') s=CONTENT;
        break;
      case CONTENT:
        if(c=='<') s=LABLE;
        else{
          //去掉content中的'\n' 最终我们要使用'\n'作为每个html文件的解析之后的数据之间的分隔符
          if(c=='\n') c=' ';
          content->push_back(c);
        }
        break;
      default:
        break;
    }
  }

  return true;
}

bool ParseUrl(const std::string& filepath,std::string* url)
{
  std::string url_head="https://www.boost.org/doc/libs/1_87_0/doc/html";
  std::string url_tail=filepath.substr(src_path.size());
  *url=url_head+url_tail;
  return true;

}


/*void ShowDoc(const DocInfo_t & doc)
{
    std::cout << "title: " << doc.title << std::endl;
    std::cout << "content: " << doc.content << std::endl;
    std::cout << "url: " << doc.url << std::endl;
}*/



bool ParseHtml(const std::vector<std::string>&file_list,std::vector<DocInfo_t>* results)
{

  for(const std::string& filepath:file_list)
  {
    //1.依次读取file_list中的文件到result中
    std::string result;
    if(!ns_util::FileUtil::ReadFile(filepath,&result))
    {
      continue;
    }
    DocInfo_t doc;
    //2.读取文件成功，开始进文件内容分析，提取文件title
    if(!ParseTitle(result,&doc.title))
    {
      continue;
    }
    //3.提取title成功，提取content
    if(!ParseContent(result,&doc.content))
    {
      continue;
    }
    //4.提取content成功，提取url
    if(!ParseUrl(filepath,&doc.url))
    {
      continue;
    }
    //将doc转为右值之后插入，可以减少拷贝
    results->push_back(std::move(doc));
    
   // ShowDoc(doc);
   // break;
  }

  return true;

}


bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output)
{
#define SEP '\3'
  //按照二进制方式写入
  std::ofstream out(output,std::ios::out | std::ios::binary);
  if(!out.is_open())
  {
   // std::cerr<<"open"<<output<<"failed!"<<std::endl;
    LOG(WARNING,"open"+output+"failed!");
    return false;
  }
  //打开了文件，开始进行数据的写入
  for(auto &item:results)
  {
    std::string out_string;
    out_string += item.title;
    out_string += SEP;
    out_string +=item.content;
    out_string+=SEP;
    out_string+=item.url;
    out_string += '\n';

    out.write(out_string.c_str(),out_string.size());
  }

  return true;
}
